package com.developer.platform.domain.scheduler;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.developer.platform.domain.QuartzJob;
import com.developer.platform.infrastructure.data.mapper.QuartzJobMapper;
import com.developer.platform.infrastructure.enums.StatusEnum;
import com.veeker.core.utils.JsonUtils;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

/**
 * @author ：qiaoliang
 * @date ：2021-01-07
 */
@Component
public class QuartzScheduler implements ApplicationListener<ContextRefreshedEvent> {

  private final QuartzJobMapper quartzJobMapper;
  private final Scheduler scheduler;

  public QuartzScheduler(
      QuartzJobMapper quartzJobMapper,
      Scheduler scheduler) {
    this.quartzJobMapper = quartzJobMapper;
    this.scheduler = scheduler;
  }

  public void startJob() throws SchedulerException {
    List<QuartzJob> list = this.list();
    for (QuartzJob quartzJob : list) {
      this.addJob(quartzJob);
    }
    scheduler.start();
  }

  public void addJob(QuartzJob quartzJob) {
    try {
      this.deleteJob(quartzJob.getName(), quartzJob.getSubgroup());
      Class aClass = Class.forName(quartzJob.getJobClass());
      Map map = JsonUtils.toBean(quartzJob.getJobData(), Map.class);
      JobDetail jobDetail = JobBuilder
          .newJob(aClass).withIdentity(quartzJob.getName(), quartzJob.getSubgroup())
          // 添加一些参数，执行的时候用
          .usingJobData(new JobDataMap(map))
          .build();
      // 基于表达式构建触发器
      CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(quartzJob.getCore());
      // CronTrigger表达式触发器 继承于Trigger
      // TriggerBuilder 用于构建触发器实例
      CronTrigger cronTrigger = TriggerBuilder
          .newTrigger().withIdentity(quartzJob.getName(), quartzJob.getSubgroup())
          .withSchedule(cronScheduleBuilder).build();
      scheduler.scheduleJob(jobDetail, cronTrigger);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public void deleteJob(String name, String group) {
    try {
      JobKey jobKey = new JobKey(name, group);
      JobDetail jobDetail = this.scheduler.getJobDetail(jobKey);
      if (Objects.nonNull(jobDetail)){
        this.scheduler.deleteJob(jobKey);
      }
    } catch (SchedulerException e) {
      e.printStackTrace();
    }
  }

  public List<QuartzJob> list(){
    LambdaQueryWrapper<QuartzJob> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(QuartzJob::getStatus, StatusEnum.N);
    return quartzJobMapper.selectList(queryWrapper);
  }

  @Override
  public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
    try {
      this.startJob();
    } catch (SchedulerException e) {
      e.printStackTrace();
    }
  }
}
